#include "server.h"
#include "receiver.h"
#include "config/applicationconfiguration.h"

Server::Server() : tcpServer(0)
{
}

void Server::run()
{
    tcpServer = new QTcpServer(this);
    if (!tcpServer->listen(QHostAddress::Any, ApplicationConfiguration::myHost.getPort())) {
        qDebug() << "Nie udało się włączyć serwera - " << tcpServer->errorString();
        exit(EXIT_FAILURE);
    }

    QString ipAddress;
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    // use the first non-localhost IPv4 address
    for (int i = 0; i < ipAddressesList.size(); ++i) {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
            ipAddressesList.at(i).toIPv4Address()) {
            ipAddress = ipAddressesList.at(i).toString();
            break;
        }
    }
    // if we did not find one, use IPv4 localhost
    if (ipAddress.isEmpty())
        ipAddress = QHostAddress(QHostAddress::LocalHost).toString();

    // accept new connection when new client connects to server
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(acceptClientConnection()));

    emit serverStarted("Serwer uruchomiony w konfiguracji: " + ipAddress + ":" + QString("%1").arg(tcpServer->serverPort()));
}

void Server::acceptClientConnection()
{
    // get new connection' socket
    QTcpSocket *clientConnection = tcpServer->nextPendingConnection();

    // save new socket in client sockets list
    clientConnections.push_back(clientConnection);

    connect(clientConnection, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError)));

    emit clientConnected(clientConnection->peerAddress().toString());

    Receiver *worker = new Receiver(clientConnection);
    QThread *workerThread = new QThread(this);

    // receive data when data comes from client
    connect(clientConnection, SIGNAL(readyRead()), worker, SLOT(receiveData()));

    // finish client thread when clients disconnects
    connect(clientConnection, SIGNAL(disconnected()), workerThread, SLOT(quit()));

    // remove client socket from client sockets list
    connect(clientConnection, SIGNAL(disconnected()), this, SLOT(removeClientConnection()));

    // delete connection when client disconnects
    connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));

    // delete worker object when thread finishes
    connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));

    // forward loggin message from receiver thread to server thread
    connect(worker, SIGNAL(scheduleMessageLog(QString)), this, SLOT(logMessage(QString)));

    worker->moveToThread(workerThread);

    // start receiving data in a new thread
    workerThread->start();
}

void Server::removeClientConnection(){

    // remove socket which emitted disconnected() signal
    clientConnections.removeOne((QTcpSocket*)QObject::sender());

    emit clientDisconnected(((QTcpSocket*)QObject::sender())->peerAddress().toString());
}

void Server::logMessage(QString msg){
    emit logMsg(msg);
}

void Server::connectionError(QAbstractSocket::SocketError err){
    QTcpSocket* connection = (QTcpSocket*)QObject::sender();
    emit logMsg(connection->errorString() + "\n");
}
